"""
@description: Server of the backend (CV end).
@author: ZDZ, GHY
@create: 2022/07/13
"""
import cv2
import tensorflow.keras.backend as K
from flask import Flask, Response
from flask_cors import CORS
from api.detect_strangers_and_emotion import StrangerEmotionDetector
from api.detect_fall import FallDetector
from api.detect_interaction import InteractionDetector
from api.detect_region_invasion import RegionInvasionDetector
from elderlyCare.utils.oss_utils import oss_upload

# constants
HOST_NAME = "0.0.0.0"
PORT_NO = 9663
IS_DEBUG = False
IS_THREADED = True

IS_AVAILABLE = "available"
IS_USING = "using"

SPRING_EVENT_ADD_URL = "http://zzay0132.mynatapp.cc/event/add"

OUTPUT_STRANGER_PATH = "D:\\Develop\\pycharmWorkspace\\Intelligent-Endowment\\generate\\supervision\\strangers"
OUTPUT_SMILE_PATH = "D:\\Develop\\pycharmWorkspace\\Intelligent-Endowment\\generate\\supervision\\smile"

OUTPUT_FALL_IMAGE_PATH = "D:\\Develop\\pycharmWorkspace\\Intelligent-Endowment\\generate\\supervision\\fall"

OUTPUT_INTERACTION_PATH = "D:\\Develop\\pycharmWorkspace\\Intelligent-Endowment\\generate\\supervision\\interaction"

OUTPUT_REGION_INVASION_PATH = "D:\\Develop\\pycharmWorkspace\\Intelligent-Endowment\\generate\\supervision\\region-invasion"

# global variables
cv_state = IS_AVAILABLE

video_camera = None
global_frame = None

# app
app = Flask(__name__)
CORS(app, supports_credentials=True)


def video_stream():
    """
    Generate video stream and return.
    :return: Video stream
    """
    global video_camera
    global global_frame

    if video_camera is None:
        video_camera = cv2.VideoCapture(0)

    # continuously capture frame
    while True:
        frame = video_camera.get_frame()
        if frame is not None:
            global_frame = frame
            yield (b'--frame\r\n'
                   b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')
        else:
            yield (b'--frame\r\n'
                   b'Content-Type: image/jpeg\r\n\r\n' + global_frame + b'\r\n\r\n')


def release():
    """
    Release camera and destroy all windows.
    :return: Release camera and destroy all windows.
    """
    global cv_state
    global video_camera

    del video_camera
    video_camera = None
    cv_state = IS_AVAILABLE

    oss_upload(OUTPUT_STRANGER_PATH)
    oss_upload(OUTPUT_SMILE_PATH)
    oss_upload(OUTPUT_FALL_IMAGE_PATH)
    oss_upload(OUTPUT_INTERACTION_PATH)
    oss_upload(OUTPUT_REGION_INVASION_PATH)


@app.route("/strangerAndEmotion", methods=["GET", "POST"])
def detect_stranger_emotion():
    """
    Detect strangers and emotions of the elderly.
    :return: Detection of strangers and emotions of the elderly
    """
    global cv_state

    release()
    # if the camera is not available
    if cv_state != IS_AVAILABLE:
        return {
            "data": "The camera is not available now",
            "status": cv_state
        }

    K.clear_session()
    global video_camera
    cv_state = IS_USING
    video_camera = StrangerEmotionDetector(url=SPRING_EVENT_ADD_URL)
    return Response(response=video_stream(),
                    status=200,
                    mimetype="multipart/x-mixed-replace; boundary=frame")


@app.route("/detectFall", methods=["GET", "POST"])
def detect_fall():
    """
    Detect falling of the elderly.
    :return: Detection of potential falling of the elderly
    """
    global cv_state

    release()
    # if the camera is not available
    if cv_state != IS_AVAILABLE:
        return {
            "data": "The camera is not available now",
            "status": cv_state
        }

    K.clear_session()
    global video_camera
    cv_state = IS_USING
    video_camera = FallDetector(url=SPRING_EVENT_ADD_URL)
    return Response(response=video_stream(),
                    mimetype="multipart/x-mixed-replace; boundary=frame")


@app.route('/detectRegionInvasion', methods=["GET", "POST"])
def detect_region_invasion():
    """
    Detect whether someone goes in or out of a certain area (fence).
    :return: Detection of region invasion.
    """
    global cv_state

    release()
    # if the camera is not available
    if cv_state != IS_AVAILABLE:
        return {
            "data": "The camera is not available now",
            "status": cv_state
        }

    K.clear_session()
    global video_camera
    cv_state = IS_USING
    video_camera = RegionInvasionDetector(url=SPRING_EVENT_ADD_URL)
    return Response(response=video_stream(),
                    mimetype="multipart/x-mixed-replace; boundary=frame")


@app.route("/detectInteraction", methods=["GET", "POST"])
def detect_interaction():
    """
    Detection of interaction activity.
    :return: Detection result of interaction activity
    """
    global cv_state

    release()
    # if the camera is not available
    if cv_state != IS_AVAILABLE:
        return {
            "data": "The camera is not available now",
            "status": cv_state
        }

    K.clear_session()
    global video_camera
    cv_state = IS_USING
    video_camera = InteractionDetector(url=SPRING_EVENT_ADD_URL)
    return Response(response=video_stream(),
                    mimetype='multipart/x-mixed-replace; boundary=frame')


@app.route("/status", methods=["GET"])
def status():
    """
    Return the status of the camera.
    :return: Status of the camera
    """
    return {
        "data": "Return the status of the camera",
        "status": cv_state
    }


# @app.route("/close", methods=["GET"])
def close():
    """
    Release camera and destroy all windows.
    :return: Release camera and destroy all windows.
    """
    global cv_state
    global video_camera

    del video_camera
    video_camera = None
    cv2.destroyAllWindows()
    cv_state = IS_AVAILABLE

    return {
        "data": "Release camera and destroy all windows",
        "status": cv_state
    }


if __name__ == '__main__':
    """
    Update constants above if modifications are required.
    """
    app.run(host=HOST_NAME,
            port=PORT_NO,
            debug=IS_DEBUG,
            threaded=IS_THREADED)
